package com.bit.websocket;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;

import static io.netty.handler.codec.http.HttpHeaderUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpHeaderUtil.setContentLength;

public class WebSocketServerHandler extends SimpleChannelInboundHandler {

    private WebSocketServerHandshaker handshaker;

    protected void messageReceived(ChannelHandlerContext context, Object o) throws Exception {
        // 第一次HTTP传入
        if(o instanceof FullHttpRequest){
            handlerHttpRequest(context, (FullHttpRequest)o);
        }
        // websocket协议
        else if (o instanceof WebSocketFrame){
            handlerWebSocketFrame(context, (WebSocketFrame)o);
        }
    }

    private void handlerWebSocketFrame(ChannelHandlerContext context, WebSocketFrame frame) {
        // 判断是否是关闭链路的指令
        if(frame instanceof CloseWebSocketFrame){
            handshaker.close(context.channel(), (CloseWebSocketFrame) frame.retain());
            return;
        }
        // 判断是否是Ping消息
        if(frame instanceof PingWebSocketFrame){
            context.channel().write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        //
//        if()
    }

    private void handlerHttpRequest(ChannelHandlerContext context, FullHttpRequest req) {
        if(!req.decoderResult().isSuccess()
                || (!"websocket".equals(req.headers().get("Upgrade")))){
            sendHttpResponse(context, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }

        //构造握手响应返回
        WebSocketServerHandshakerFactory wsFactory =
                new WebSocketServerHandshakerFactory("ws://localhost:8080/websocket", null,false);
        handshaker = wsFactory.newHandshaker(req);
        if(handshaker == null){
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(context.channel());
        }else {
            handshaker.handshake(context.channel(), req);
        }
    }

    private void sendHttpResponse(ChannelHandlerContext context, FullHttpRequest req, FullHttpResponse resp) {
       if(resp.status().code() != 200){
           ByteBuf buf = Unpooled.copiedBuffer(resp.status().toString(), CharsetUtil.UTF_8);
           resp.content().writeBytes(buf);
           buf.release();
           setContentLength(resp, resp.content().readableBytes());
       }
       //如果是非Keep-Alive,关闭连接
        ChannelFuture channelFuture = context.channel().writeAndFlush(resp);
       if(!isKeepAlive(req) || resp.status().code()!=200){
           channelFuture.addListener(ChannelFutureListener.CLOSE);
       }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
